/**
 * 项目名称：捕捉按键输入
 * 单片机：STC8G1K08
 * 频率：12Mhz
 * PCB:1603120A_Y3
 * 学习目标：捕捉按键消除抖动
 */

#include "intrins.h"
#include "stc8g.h" //加载此头文件以后不需要再加载reg51.h

#define FOSC 11059200UL              //时钟频率
#define BRT (256 - FOSC / 9600 / 32) // 8位自动重载初始值

#define LED_0 P35
#define LED_1 P34
#define LED_2 P10
#define LED_3 P11
#define LED_4 P16
#define LED_5 P17
#define LED_6 P54
#define LED_7 P55

#define KEY_1 P32
#define KEY_2 P33

#define KEY_NONE 0x00 // 00
#define KEY_DOWN 0x01 // 01
#define KEY_LONG 0x02 // 10
#define KEY_MASK 0x03 // 11

unsigned char ledState; // led状态
unsigned char bits;
volatile unsigned char timer2_t = 20; // 1000 / 50 = 20

volatile unsigned char keyState; //按键状态 每2个bit表达一个按键

bit busy;                 //串口繁忙标志
unsigned char wptr;       //接收字节计数器
unsigned char rptr;       //发送字节计数器
unsigned char buffer[16]; //串口缓冲区

void led_update_display();

//串口实始化，对应数据手册查看每个寄存器是如何配置的
void uart1_init() {
    SCON = 0x50; // SCON：SM=10,模式1，REN=1允许接收数据
    TMOD = 0x20; // TMOD：定时器0和1模式寄存器 0x20 = 0010 0000
    TL1 = BRT;
    TH1 = BRT;
    AUXR &= ~0x01;       // S1ST2=0;定时器1作为波特率发生器 默认为定时器2做为发生器
    AUXR |= (0x01 << 6); // T1x12=1，定时器工作在1T模式
    TR1 = 1;             //定时器1开始计数
    ES = 1;              //使能串口中断
    wptr = 0;
    rptr = 0;
    busy = 0;
}

//发送一个字节
void uart_send(unsigned char dat) {
    while (busy)
        ;
    busy = 1;   //先标记发送繁忙
    SBUF = dat; //向数据写入串口的发送缓冲区
}

void rcv_uart_data(unsigned char dat) {
    if (buffer[0] == 0x7E) {
        buffer[wptr++] = dat;
        wptr &= 0x0F; //防止buffer溢出
        return;
    }
    buffer[0] = dat;
    wptr = 1;
}

//串口1 中断函数 接收完成或发送完毕都会产生中断
void uart_ISR() interrupt 4 {
    //发送已完成时
    if (TI) {
        TI = 0;   //将中断软件清零
        busy = 0; //繁忙标记清零
    }

    //接收到1个字节时
    if (RI) {
        RI = 0; //将接收中断标志清零
        rcv_uart_data(SBUF);
        // buffer[wptr++] = SBUF; //读取串口缓冲寄存器
        // wptr &= 0x0F;          //防止buffer溢出
    }
}

//解析串口数据
void decode_uart_data() {
    if (wptr < 2) {
        return;
    }

    if (buffer[0] == 0x7E) {
        ledState = buffer[1];
        led_update_display();
    }

    //不管数据是否合法，将接收缓存清空，并将wptr归零，以便接收新的数据
    wptr = 0;
    buffer[0] = 0x00;
    buffer[1] = 0x00;
}

//发送LED状态
void send_led_state() {
    uart_send(0x7E);
    uart_send(ledState);
}

//@12.000MHz
void Delay10ms() {
    unsigned char i, j;

    _nop_();
    _nop_();
    i = 156;
    j = 213;
    do {
        while (--j)
            ;
    } while (--i);
}

//刷新LED状态
void led_update_display() {
    LED_0 = ledState & (0x01 << 0);
    LED_1 = ledState & (0x01 << 1);
    LED_2 = ledState & (0x01 << 2);
    LED_3 = ledState & (0x01 << 3);
    LED_4 = ledState & (0x01 << 4);
    LED_5 = ledState & (0x01 << 5);
    LED_6 = ledState & (0x01 << 6);
    LED_7 = ledState & (0x01 << 7);
}

//初始化IO
void pin_init() {
    P1M1 = 0x00;
    P1M0 = (0x01 << 7) | (0x01 << 6) | (0x01 << 1) | (0x01 << 0);

    // P3M1 = (0x01 << 3) | (0x01 << 2);
    P3M1 = 0x00;
    P3M0 = (0x01 << 5) | (0x01 << 4);

    P5M1 = 0x00;
    P5M0 = (0x01 << 5) | (0x01 << 4);
}

//定时器2 初始化 10ms@11.0592MHz
void timer2_init() {
    AUXR &= 0xE3;        // T2相关位置零
    AUXR |= (0x01 << 2); //定时器时钟12T模式
    T2L = 0x00;          //设置定时初值
    T2H = 0xDC;          //设置定时初值
    AUXR |= (0x01 << 4); //定时器2开始计时
    IE2 |= 0x04;         // ET2 置1 使能(允许)定时器2中断
}

//位移LED，每调用1次左移1个位
void shift_led() {
    bits++;
    if (bits >= 8) {
        bits = 0;
    }
    ledState = 0x01 << bits;
}

// avoid vibrat
void scan_key_1_vibrate() {
    static unsigned char last = 0xFF;
    //按键状态没有被清除，不再扫描

    if (keyState & KEY_MASK) {
        return;
    }

    //下降沿
    if (!KEY_1 && last) {
        keyState |= KEY_DOWN;
    }
    last = KEY_1;
}

//延时消抖
void scan_key_2_avoid_vibrate() {
    static unsigned char last = 0xFF;
    //下降沿
    if (!KEY_2 && last) {
        Delay10ms();          //延时等待抖动过去
        shift_led();          //移位
        led_update_display(); //刷新显示
    }
    last = KEY_2;
}

void main() {

    pin_init();
    timer2_init();
    uart1_init();
    Delay10ms();
    ledState = 0x01;
    bits = 0;
    led_update_display(); //刷新显示

    keyState = 0x00;

    EA = 1; //使能总中断 (打开中断总开关)

    while (1) {
        // scan_key_1_vibrate();  //放在这里是轮询
        scan_key_2_avoid_vibrate();
        decode_uart_data();

        if ((keyState & KEY_MASK) == KEY_DOWN) {
            ledState = ~ledState;  //反向显示
            led_update_display();  //刷新显示
            send_led_state();      //向上位机发送状态
            keyState &= ~KEY_MASK; //清除按键状态
        }
    }
}

//定时器2 中断函数
void time2_ISR() interrupt 12 {
    scan_key_1_vibrate(); //放在这里是就是用定时器扫描
}
